أطلق العنان لقدرات الوقت الفعلي في مشاريع Django الخاصة بك باستخدام Django Channels و WebSockets. يقدم هذا الدليل الشامل شرحًا تفصيليًا للتنفيذ وأفضل الممارسات والتقنيات المتقدمة.
بايثون Django Channels: دليل شامل لتنفيذ WebSocket
في مشهد الويب الديناميكي اليوم، لم تعد تطبيقات الوقت الفعلي رفاهية بل ضرورة. من تطبيقات الدردشة المباشرة وأدوات التحرير التعاونية إلى الألعاب عبر الإنترنت ولوحات معلومات البيانات في الوقت الفعلي، يتزايد الطلب على الاتصال والتحديثات الفورية باستمرار. لحسن الحظ، يوفر إطار عمل Django الخاص ببايثون حلاً قويًا لبناء مثل هذه التطبيقات: Django Channels.
يقدم هذا الدليل استكشافًا شاملاً لـ Django Channels وتنفيذ WebSocket الخاص به. سنتعمق في المفاهيم الأساسية، ونسير خلال مثال عملي، ونناقش التقنيات المتقدمة لمساعدتك في إنشاء تطبيقات قوية وقابلة للتطوير في الوقت الفعلي باستخدام Django.
فهم Django Channels
تعمل Django Channels على توسيع قدرات Django إلى ما بعد دورة الطلب والاستجابة التقليدية، مما يتيح الاتصال غير المتزامن والاتصالات المستمرة. تحقق ذلك من خلال تقديم واجهة بوابة الخادم غير المتزامن (ASGI)، وهو خليفة روحي لـ WSGI (واجهة بوابة خادم الويب)، وهي الواجهة المتزامنة التقليدية لـ Django.
المفاهيم الأساسية
- ASGI (واجهة بوابة الخادم غير المتزامن): ASGI هي واجهة قياسية بين تطبيقات الويب غير المتزامنة لبايثون والخوادم. يسمح لـ Django بمعالجة الاتصالات طويلة الأمد، مثل WebSockets، التي تظل مفتوحة لفترات طويلة.
- طبقات القنوات: توفر طبقات القنوات العمود الفقري للاتصال لتوزيع الرسائل بين أجزاء مختلفة من تطبيقك. فكر في الأمر على أنه قائمة انتظار رسائل أو نظام نشر / اشتراك. تتضمن التطبيقات الشائعة Redis وطبقات القنوات الموجودة في الذاكرة للتطوير وخدمات المراسلة المستندة إلى السحابة.
- المستهلكون: المستهلكون هم النظراء غير المتزامنين لطرق عرض Django. إنهم يتعاملون مع الرسائل الواردة وينفذون الإجراءات بناءً على محتوى الرسالة. يمكن كتابة المستهلكين كوظائف أو فئات، مما يوفر المرونة وقابلية إعادة الاستخدام.
- التوجيه: يحدد التوجيه كيفية توجيه الرسائل الواردة إلى مستهلكين محددين. إنه مشابه لتوجيه URL الخاص بـ Django، ولكن لاتصالات WebSocket.
إعداد مشروع Django الخاص بك باستخدام Channels
لنبدأ بإعداد مشروع Django وتثبيت Django Channels. يفترض هذا القسم أن لديك بايثون و Django مثبتين.
1. إنشاء مشروع Django جديد
افتح جهازك الطرفي وأنشئ مشروع Django جديدًا:
django-admin startproject myproject
cd myproject
2. إنشاء بيئة افتراضية (موصى به)
من الممارسات الجيدة دائمًا إنشاء بيئة افتراضية لعزل تبعيات مشروعك:
python3 -m venv venv
source venv/bin/activate # On Linux/macOS
.\\venv\\Scripts\\activate # On Windows
3. تثبيت Django Channels
قم بتثبيت Django Channels وتبعياته باستخدام pip:
pip install channels daphne
Daphne هو خادم ASGI الذي سنستخدمه لتشغيل تطبيق Channels الخاص بنا. تعتبر خوادم ASGI الأخرى مثل uvicorn متوافقة أيضًا.
4. تكوين إعدادات Django
افتح ملف `settings.py` الخاص بمشروعك وأضف `channels` إلى قائمة `INSTALLED_APPS`:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels',
# Your other apps
]
أضف تكوين تطبيق ASGI إلى `settings.py`:
ASGI_APPLICATION = 'myproject.asgi.application'
يخبر هذا Django باستخدام تطبيق ASGI المحدد في `myproject/asgi.py`.
5. تكوين طبقة Channels
قم بتكوين طبقة Channels في `settings.py`. بالنسبة للتطوير، يمكنك استخدام طبقة القناة الموجودة في الذاكرة. بالنسبة للإنتاج، يعد Redis خيارًا شائعًا. سنستخدم Redis في هذا المثال. تأكد من تثبيت Redis وتشغيله على جهازك.
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
إذا لم يكن لديك `channels_redis` مثبتًا، فقم بتثبيته:
pip install channels_redis
6. إنشاء asgi.py
إذا لم يكن موجودًا، فقم بإنشاء ملف `asgi.py` في دليل مشروعك (بجانب `wsgi.py`). يحدد هذا الملف تطبيق ASGI:
# myproject/asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing # Import your app's routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
بناء تطبيق دردشة بسيط
لنقم ببناء تطبيق دردشة بسيط لعرض Django Channels و WebSockets. سيسمح هذا المثال للمستخدمين بإرسال واستقبال الرسائل في غرفة دردشة واحدة.
1. إنشاء تطبيق Django جديد
قم بإنشاء تطبيق Django جديد يسمى `chat`:
python manage.py startapp chat
أضف `chat` إلى قائمة `INSTALLED_APPS` في `settings.py`:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels',
'chat',
# Your other apps
]
2. تحديد توجيه WebSocket
قم بإنشاء ملف `routing.py` في تطبيق `chat` لتحديد توجيه WebSocket:
# chat/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>\\w+)/$', consumers.ChatConsumer.as_asgi()),
]
يحدد هذا مسارًا لاتصالات WebSocket إلى `/ws/chat/
3. إنشاء مستهلك
قم بإنشاء ملف `consumers.py` في تطبيق `chat` لتحديد `ChatConsumer`:
# chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = f'chat_{self.room_name}'
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
username = text_data_json['username'] # Extract username from the received data
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat.message',
'message': message,
'username': username,
}
)
# Receive message from room group
async def chat_message(self, event):
message = event['message']
username = event['username']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message,
'username': username,
}))
يتعامل هذا المستهلك مع اتصالات WebSocket، وينضم إلى غرف الدردشة ويتركها، ويتلقى رسائل من العملاء، ويبث الرسائل إلى مجموعة الغرفة. الأهم من ذلك، أنه غير متزامن، مما يسمح له بمعالجة اتصالات متعددة في وقت واحد.
4. إنشاء قالب بسيط
قم بإنشاء ملف `templates/chat/room.html` في مشروعك. قد تحتاج إلى إنشاء دليل `templates` في الدليل الجذر لمشروعك ثم دليل `chat` بداخله. سيعرض هذا القالب غرفة الدردشة ويسمح للمستخدمين بإرسال الرسائل.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<h1>Chat Room: {{ room_name }}</h1>
<div id="chat-log"></div>
<input type="text" id="chat-message-input" size="100"/><br/>
<input type="text" id="chat-username-input" size="100" placeholder="Enter your username"/><br/>
<button id="chat-message-submit">Send</button>
<script>
const roomName = {{ room_name|json_script:"room-name" }};
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/chat/'
+ roomName
+ '/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').value += (data.username + ': ' + data.message + '\\n');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
document.querySelector('#chat-message-submit').onclick = function(e) {
const messageInputDom = document.querySelector('#chat-message-input');
const usernameInputDom = document.querySelector('#chat-username-input');
const message = messageInputDom.value;
const username = usernameInputDom.value; // Get the username
chatSocket.send(JSON.stringify({
'message': message,
'username': username
}));
messageInputDom.value = '';
};
</script>
</body>
</html>
يستخدم هذا القالب JavaScript لإنشاء اتصال WebSocket وإرسال الرسائل وعرض الرسائل المستلمة في عنصر `chat-log`. يتضمن الآن أيضًا حقل إدخال اسم المستخدم ويرسل اسم المستخدم مع كل رسالة.
5. إنشاء طريقة عرض
قم بإنشاء ملف `views.py` في تطبيق `chat` لتحديد طريقة عرض تعرض قالب غرفة الدردشة:
# chat/views.py
from django.shortcuts import render
def room(request, room_name):
return render(request, 'chat/room.html', {
'room_name': room_name
})
6. تحديد أنماط URL
قم بتضمين عناوين URL لتطبيق الدردشة في ملف `urls.py` الخاص بمشروعك:
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('chat/', include('chat.urls')),
]
قم بإنشاء ملف `urls.py` في تطبيق `chat`:
# chat/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('<str:room_name>/', views.room, name='room'),
]
7. تشغيل خادم التطوير
ابدأ تشغيل خادم تطوير Django باستخدام Daphne:
python manage.py runserver
افتح متصفح الويب الخاص بك وانتقل إلى `http://127.0.0.1:8000/chat/myroom/` (استبدل `myroom` باسم غرفة الدردشة المطلوبة). يجب أن ترى واجهة غرفة الدردشة. افتح نفس عنوان URL في نافذة متصفح أخرى لمحاكاة مستخدمين متعددين.
التقنيات المتقدمة وأفضل الممارسات
الآن بعد أن أصبح لديك تطبيق دردشة أساسي قيد التشغيل، دعنا نستكشف بعض التقنيات المتقدمة وأفضل الممارسات لإنشاء تطبيقات قوية وقابلة للتطوير في الوقت الفعلي باستخدام Django Channels.
المصادقة والتفويض
يعد تأمين اتصالات WebSocket الخاصة بك أمرًا بالغ الأهمية. يوفر Django Channels دعمًا مضمنًا للمصادقة والتفويض. يمكنك استخدام نظام المصادقة القياسي في Django لمصادقة المستخدمين قبل الاتصال بـ WebSocket. تقوم `AuthMiddlewareStack` في ملف `asgi.py` الخاص بك بمصادقة المستخدمين تلقائيًا بناءً على جلستهم. يمكنك الوصول إلى المستخدم المصادق عليه عبر `self.scope['user']` في المستهلك الخاص بك.
مثال:
# chat/consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
user = self.scope['user']
if user.is_authenticated:
await self.accept()
else:
await self.close()
بالنسبة لسيناريوهات التفويض الأكثر تعقيدًا، يمكنك تنفيذ برامج وسيطة مخصصة أو عمليات فحص داخل المستهلكين لديك.
قابلية التوسع والأداء
مع نمو تطبيقك، يصبح قابلية التوسع مصدر قلق بالغ. تم تصميم Django Channels ليكون قابلاً للتطوير، ولكنك تحتاج إلى مراعاة عدة عوامل:
- طبقة القنوات: اختر طبقة قنوات قوية وقابلة للتطوير، مثل Redis أو خدمة مراسلة مستندة إلى السحابة مثل Amazon MQ أو Google Cloud Pub/Sub. Redis هي نقطة انطلاق جيدة، ولكن بالنسبة للتطبيقات ذات حركة المرور العالية، فكر في حل سحابي مُدار.
- خادم ASGI: استخدم خادم ASGI جاهز للإنتاج مثل Daphne أو Uvicorn. تم تصميم هذه الخوادم للتعامل مع عدد كبير من الاتصالات المتزامنة بكفاءة.
- التحجيم الأفقي: قم بتوزيع مثيلات متعددة لتطبيق Django الخاص بك خلف موازن تحميل لتوزيع عبء العمل. يجب أن يتصل كل مثيل بنفس طبقة القنوات.
- تحسين قاعدة البيانات: إذا كان تطبيقك يتضمن تفاعلات مع قاعدة البيانات، فقم بتحسين استعلامات قاعدة البيانات الخاصة بك وفكر في استخدام التخزين المؤقت لتقليل تحميل قاعدة البيانات.
الاختبار
يعد اختبار تطبيقات Channels الخاصة بك أمرًا ضروريًا لضمان موثوقيتها وصحتها. يوفر Django Channels أدوات اختبار لمحاكاة اتصالات WebSocket والتحقق من سلوك المستهلكين لديك.
مثال:
# chat/tests.py
import pytest
from channels.testing.websocket import WebsocketCommunicator
from chat.consumers import ChatConsumer
@pytest.mark.asyncio
async def test_chat_consumer():
communicator = WebsocketCommunicator(ChatConsumer.as_asgi(), "ws/chat/testroom/")
connected, subprotocol = await communicator.connect()
assert connected
await communicator.send_to(text_data={"message": "Hello", "username": "TestUser"})
response = await communicator.receive_from()
assert response == '{"message":"Hello","username":"TestUser"}'
await communicator.disconnect()
يستخدم هذا المثال `WebsocketCommunicator` لمحاكاة اتصال WebSocket بـ `ChatConsumer`، وإرسال رسالة، والتحقق من الاستجابة.
معالجة الأخطاء
تعد معالجة الأخطاء القوية أمرًا بالغ الأهمية لمنع أعطال التطبيقات وتوفير تجربة مستخدم جيدة. قم بتنفيذ معالجة الأخطاء المناسبة في المستهلكين لديك لالتقاط الاستثناءات والتعامل مع المواقف غير المتوقعة بأمان. يمكنك استخدام كتل `try...except` لالتقاط الاستثناءات وإرسال رسائل الخطأ إلى العملاء.
مثال:
# chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def receive(self, text_data):
try:
text_data_json = json.loads(text_data)
message = text_data_json['message']
username = text_data_json['username']
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat.message',
'message': message,
'username': username
}
)
except Exception as e:
await self.send(text_data=json.dumps({
'error': str(e)
}))
اعتبارات النشر
يتطلب نشر تطبيقات Django Channels تخطيطًا ودراسة متأنيين. فيما يلي بعض الجوانب الرئيسية التي يجب وضعها في الاعتبار:
- خادم ASGI: استخدم خادم ASGI بدرجة إنتاج مثل Daphne أو Uvicorn. قم بتكوين الخادم للتعامل مع عدد كبير من الاتصالات المتزامنة وتحسين الأداء.
- طبقة القنوات: اختر طبقة قنوات موثوقة وقابلة للتطوير. Redis هو خيار جيد للتطبيقات الصغيرة والمتوسطة الحجم، ولكن بالنسبة للتطبيقات الأكبر حجمًا، ففكر في خدمة مراسلة مستندة إلى السحابة. تأكد من أن طبقة القنوات الخاصة بك قد تم تكوينها وتأمينها بشكل صحيح.
- موازنة التحميل: استخدم موازن تحميل لتوزيع حركة المرور عبر مثيلات متعددة لتطبيق Django الخاص بك. سيؤدي ذلك إلى تحسين الأداء وضمان التوفر العالي.
- المراقبة: قم بتنفيذ مراقبة شاملة لتتبع أداء تطبيقك وتحديد المشكلات المحتملة. راقب عدد اتصالات WebSocket النشطة وإنتاجية الرسائل ومعدلات الخطأ.
- الأمان: قم بتأمين اتصالات WebSocket الخاصة بك باستخدام تشفير SSL/TLS. قم بتنفيذ آليات المصادقة والتفويض المناسبة لحماية تطبيقك من الوصول غير المصرح به.
حالات الاستخدام بخلاف تطبيقات الدردشة
على الرغم من أن مثالنا ركز على تطبيق دردشة، إلا أن Django Channels متعدد الاستخدامات ويمكن تطبيقه على مجموعة واسعة من تطبيقات الوقت الفعلي. فيما يلي بعض الأمثلة:
- لوحات معلومات البيانات في الوقت الفعلي: عرض تحديثات البيانات المباشرة في لوحات المعلومات لمراقبة أداء النظام أو الأسواق المالية أو اتجاهات وسائل التواصل الاجتماعي. على سبيل المثال، يمكن لمنصة تداول مالية استخدام Django Channels لدفع أسعار الأسهم في الوقت الفعلي إلى المستخدمين.
- أدوات التحرير التعاونية: تمكين العديد من المستخدمين من تحرير المستندات أو جداول البيانات أو التعليمات البرمجية في وقت واحد، مع انعكاس التغييرات في الوقت الفعلي. ضع في اعتبارك نظامًا أساسيًا للتحرير التعاوني للمستندات مشابهًا لـ Google Docs.
- الألعاب عبر الإنترنت: قم ببناء ألعاب متعددة اللاعبين مع تفاعلات في الوقت الفعلي بين اللاعبين. يمكن أن يتراوح هذا من ألعاب الطاولة البسيطة إلى ألعاب الحركة المعقدة.
- الإشعارات المباشرة: إرسال إشعارات في الوقت الفعلي إلى المستخدمين حول الأحداث أو التحديثات أو التنبيهات. على سبيل المثال، يمكن لمنصة التجارة الإلكترونية إعلام المستخدمين عند تغيير حالة طلبهم.
- تطبيقات إنترنت الأشياء (IoT): جمع ومعالجة البيانات من أجهزة إنترنت الأشياء في الوقت الفعلي. تخيل تطبيق منزل ذكي يتلقى بيانات المستشعر من أجهزة مختلفة ويحدث واجهة المستخدم وفقًا لذلك.
الخلاصة
يوفر Django Channels إطار عمل قوي ومرن لإنشاء تطبيقات في الوقت الفعلي باستخدام بايثون و Django. من خلال الاستفادة من WebSockets و ASGI وطبقات القنوات، يمكنك إنشاء تجارب مستخدم تفاعلية وجذابة للغاية. قدم هذا الدليل نظرة عامة شاملة على Django Channels، وتغطية المفاهيم الأساسية ومثال عملي وتقنيات متقدمة. بينما تواصل استكشاف Django Channels، ستكتشف إمكاناتها الهائلة لبناء تطبيقات مبتكرة ومؤثرة في الوقت الفعلي.
احتضن قوة البرمجة غير المتزامنة وأطلق العنان للإمكانات الكاملة لمشاريع Django الخاصة بك باستخدام Django Channels!